#ifndef _APPLICATION_H_
#define _APPLICATION_H_

#include "Uncopyable.h"
#include "EventLoop.h"

#include <Window/Window.h>
#include <memory>
#include <Event/Event.h>
#include <vector>
#include <Layer/Layer.h>
#include <Renderer/Renderer.h>
#include <Layer/ImguiLayer.h>

extern int main(int argc, char * argv[]);

namespace Engine2D
{
    struct ApplicationArgs
    {
        int argc;
        char** argv;
    };    

    class Application : public Uncopyable 
    {
    public:
        friend int ::main(int argc, char * argv[]);
    public:
        Application(ApplicationArgs args = ApplicationArgs());
        virtual ~Application();

        virtual void Init();

        template<typename T>
        static std::weak_ptr<T> Instance() { return std::dynamic_pointer_cast<T>(s_app); }

        void Run();

        void PushBackLayer(std::shared_ptr<Layer> layer) { m_layers.emplace_back(layer); layer->OnAttach(); }

        void RemoveLayer(Layer const * layer);

        std::weak_ptr<Window> GetWindow() { return m_window; }

        EventLoop& GetEventLoop() { return m_eventLoop; }

    private:
        void OnEvent(EventPtr event);
        void OnClose(EventPtr event);
        void OnResize(EventPtr event);
    private:
        ApplicationArgs m_args;
        EventLoop m_eventLoop;
        std::shared_ptr<Window> m_window;
        std::vector<std::shared_ptr<Layer>> m_layers;
        std::shared_ptr<ImguiLayer> m_imguiLayer;

        inline static std::shared_ptr<Application> s_app;
    };
} // namespace Engine2D

std::shared_ptr<Engine2D::Application> CreateApplication(Engine2D::ApplicationArgs args);

#endif